Głównymi celami projektu było dokonanie analizy bazy danych Lego oraz stworzenie modelu potrafiącego przewidywać cechy przyszłych zestawów (w moim przypadku ceny zestawu). Początkowym krokiem było odpowiednie połączenie ze sobą tabel. W przypadku połączenia zestawów Lego z liczbą minifigurek ważne było wykorzystanie połączenia zewnętrzengo, aby nie stracić zestawów bez minifigurek, a następnie zastąpienie zerami brakujących wartości liczby minifigurek. Analizowane są przede wszystkim zestawy Lego, jednak znajduje się także kilka wykresów dotyczących części Lego. Dla rozkładów wartości zauważyłem m.in. lokalne wzniesienie przy 100 częściach Lego na wykresie gęstości. W przypadku trendów na przestrzeni lat dostrzegłem m.in. spadek liczby produkowanych zestawów na początku lat 2000 oraz brak trendu dla średniej liczby minifigurek w zestawach. Do predykcji wykorzystałem obcy zbiór danych zawierający sugerowane ceny zestawów, które będą przewidywane przy użyciu modelu stworzonego przy pomocy pakietu XGBoost. Aby przygotować dane do wykorzystania przez model, skorzystałem z pakietu vtreat. Przed treningiem modelu dokonałem analizy wartości cen zestawów jak i ich zależności z rokiem, liczbą części i liczbą minifigurek. W każdym przypadku widoczna była dodatnia korelacja. Ostatecznie model uzyskał wartość RMSE równą 33.551, a uzyskane przewidywania zostały przedstawione w tabeli i na wykresie.
library(dplyr)
library(tidyr)
library(ggplot2)
library(knitr)
library(plotly)
library(xgboost)
library(vtreat)
library(DT)
opts_chunk$set(echo=FALSE)
set.seed(23)
inventories <- read.csv("data/inventories.csv")
inventory_parts <- read.csv("data/inventory_parts.csv")
parts <- read.csv("data/parts.csv")
colors <- read.csv("data/colors.csv")
part_categories <- read.csv("data/part_categories.csv")
elements <- read.csv("data/elements.csv")
part_relationships <- read.csv("data/part_relationships.csv")
inventory_minifigs <- read.csv("data/inventory_minifigs.csv")
minifigs <- read.csv("data/minifigs.csv")
inventory_sets <- read.csv("data/inventory_sets.csv")
sets <- read.csv("data/sets.csv")
themes <- read.csv("data/themes.csv")
W celu przyspieszenia obliczeń, blok ten jest cachowany.
Przykładowe wartości:
| id | version | set_num |
|---|---|---|
| 1 | 1 | 7922-1 |
| 3 | 1 | 3931-1 |
| 4 | 1 | 6942-1 |
| 15 | 1 | 5158-1 |
| 16 | 1 | 903-1 |
| 17 | 1 | 850950-1 |
Podsumowanie tabeli:
## id version set_num
## Min. : 1 Min. : 1.000 Length:37265
## 1st Qu.: 14424 1st Qu.: 1.000 Class :character
## Median : 54379 Median : 1.000 Mode :character
## Mean : 61104 Mean : 1.091
## 3rd Qu.: 88842 3rd Qu.: 1.000
## Max. :194312 Max. :16.000
Przykładowe wartości:
| inventory_id | part_num | color_id | quantity | is_spare | img_url |
|---|---|---|---|---|---|
| 1 | 48379c01 | 72 | 1 | f | https://cdn.rebrickable.com/media/parts/photos/1/48379c01-1-e7daa845-2671-4737-8642-3b1574308155.jpg |
| 1 | 48395 | 7 | 1 | f | https://cdn.rebrickable.com/media/parts/photos/7/48395-7-b9152acf-2fa5-4836-a04d-5b7fd39c2406.jpg |
| 1 | stickerupn0077 | 9999 | 1 | f | |
| 1 | upn0342 | 0 | 1 | f | |
| 1 | upn0350 | 25 | 1 | f | |
| 3 | 2343 | 47 | 1 | f | https://cdn.rebrickable.com/media/parts/elements/3000240.jpg |
Podsumowanie tabeli:
## inventory_id part_num color_id quantity
## Min. : 1 Length:1180987 Min. : -1.0 Min. : 1.00
## 1st Qu.: 9404 Class :character 1st Qu.: 4.0 1st Qu.: 1.00
## Median : 22838 Mode :character Median : 15.0 Median : 2.00
## Mean : 50849 Mean : 131.8 Mean : 3.37
## 3rd Qu.: 87088 3rd Qu.: 71.0 3rd Qu.: 4.00
## Max. :194312 Max. :9999.0 Max. :3064.00
## is_spare img_url
## Length:1180987 Length:1180987
## Class :character Class :character
## Mode :character Mode :character
##
##
##
Przykładowe wartości:
| part_num | name | part_cat_id | part_material |
|---|---|---|---|
| 003381 | Sticker Sheet for Set 663-1 | 58 | Plastic |
| 003383 | Sticker Sheet for Sets 618-1, 628-2 | 58 | Plastic |
| 003402 | Sticker Sheet for Sets 310-3, 311-1, 312-3 | 58 | Plastic |
| 003429 | Sticker Sheet for Set 1550-1 | 58 | Plastic |
| 003432 | Sticker Sheet for Sets 357-1, 355-1, 940-1 | 58 | Plastic |
| 003434 | Sticker Sheet for Set 575-2, 653-1, 460-1 | 58 | Plastic |
Podsumowanie tabeli:
## part_num name part_cat_id part_material
## Length:52615 Length:52615 Min. : 1.00 Length:52615
## Class :character Class :character 1st Qu.:17.00 Class :character
## Mode :character Mode :character Median :41.00 Mode :character
## Mean :38.91
## 3rd Qu.:60.00
## Max. :68.00
Przykładowe wartości:
| id | name | rgb | is_trans |
|---|---|---|---|
| -1 | [Unknown] | 0033B2 | f |
| 0 | Black | 05131D | f |
| 1 | Blue | 0055BF | f |
| 2 | Green | 237841 | f |
| 3 | Dark Turquoise | 008F9B | f |
| 4 | Red | C91A09 | f |
Podsumowanie tabeli:
## id name rgb is_trans
## Min. : -1.0 Length:263 Length:263 Length:263
## 1st Qu.: 83.0 Class :character Class :character Class :character
## Median :1005.0 Mode :character Mode :character Mode :character
## Mean : 651.4
## 3rd Qu.:1070.5
## Max. :9999.0
Przykładowe wartości:
| id | name |
|---|---|
| 1 | Baseplates |
| 3 | Bricks Sloped |
| 4 | Duplo, Quatro and Primo |
| 5 | Bricks Special |
| 6 | Bricks Wedged |
| 7 | Containers |
Podsumowanie tabeli:
## id name
## Min. : 1.00 Length:66
## 1st Qu.:19.25 Class :character
## Median :35.50 Mode :character
## Mean :35.36
## 3rd Qu.:51.75
## Max. :68.00
Przykładowe wartości:
| element_id | part_num | color_id | design_id |
|---|---|---|---|
| 6443403 | 2277c01pr0009 | 1 | 2277 |
| 6300211 | 67906c01 | 14 | 67908 |
| 4566309 | 2564 | 0 | 2564 |
| 4275423 | 53657 | 1004 | 53657 |
| 6194308 | 92926 | 71 | 28967 |
| 6229123 | 26561 | 4 | 26561 |
Podsumowanie tabeli:
## element_id part_num color_id design_id
## Min. : 9327 Length:84138 Min. : -1.0 Min. : 1001
## 1st Qu.: 4259774 Class :character 1st Qu.: 8.0 1st Qu.: 18454
## Median : 6057754 Mode :character Median : 28.0 Median : 41748
## Mean : 5222065 Mean : 539.7 Mean : 45570
## 3rd Qu.: 6262024 3rd Qu.: 135.0 3rd Qu.: 75475
## Max. :61532443 Max. :9999.0 Max. :107520
## NA's :23682
Przykładowe wartości:
| rel_type | child_part_num | parent_part_num |
|---|---|---|
| P | 3626cpr3662 | 3626c |
| P | 87079pr9974 | 87079 |
| P | 3960pr9971 | 3960 |
| R | 98653pr0003 | 98086pr0003 |
| R | 98653pr0003 | 98088pat0003 |
| R | 98653pr0003 | 98089pat0003 |
Podsumowanie tabeli:
## rel_type child_part_num parent_part_num
## Length:29977 Length:29977 Length:29977
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
Przykładowe wartości:
| inventory_id | fig_num | quantity |
|---|---|---|
| 3 | fig-001549 | 1 |
| 4 | fig-000764 | 1 |
| 19 | fig-000555 | 1 |
| 25 | fig-000574 | 1 |
| 26 | fig-000842 | 1 |
| 26 | fig-008641 | 1 |
Podsumowanie tabeli:
## inventory_id fig_num quantity
## Min. : 3 Length:20858 Min. : 1.000
## 1st Qu.: 7869 Class :character 1st Qu.: 1.000
## Median : 15681 Mode :character Median : 1.000
## Mean : 43010 Mean : 1.062
## 3rd Qu.: 66834 3rd Qu.: 1.000
## Max. :194312 Max. :100.000
Przykładowe wartości:
| fig_num | name | num_parts | img_url |
|---|---|---|---|
| fig-000001 | Toy Store Employee | 4 | https://cdn.rebrickable.com/media/sets/fig-000001.jpg |
| fig-000002 | Customer Kid | 4 | https://cdn.rebrickable.com/media/sets/fig-000002.jpg |
| fig-000003 | Assassin Droid, White | 8 | https://cdn.rebrickable.com/media/sets/fig-000003.jpg |
| fig-000004 | Man, White Torso, Black Legs, Brown Hair | 4 | https://cdn.rebrickable.com/media/sets/fig-000004.jpg |
| fig-000005 | Captain America with Short Legs | 3 | https://cdn.rebrickable.com/media/sets/fig-000005.jpg |
| fig-000006 | Lloyd Avatar | 5 | https://cdn.rebrickable.com/media/sets/fig-000006.jpg |
Podsumowanie tabeli:
## fig_num name num_parts img_url
## Length:13764 Length:13764 Min. : 0.000 Length:13764
## Class :character Class :character 1st Qu.: 4.000 Class :character
## Mode :character Mode :character Median : 4.000 Mode :character
## Mean : 5.296
## 3rd Qu.: 5.000
## Max. :156.000
Przykładowe wartości:
| inventory_id | set_num | quantity |
|---|---|---|
| 35 | 75911-1 | 1 |
| 35 | 75912-1 | 1 |
| 39 | 75048-1 | 1 |
| 39 | 75053-1 | 1 |
| 50 | 4515-1 | 1 |
| 50 | 4520-1 | 2 |
Podsumowanie tabeli:
## inventory_id set_num quantity
## Min. : 35 Length:4358 Min. : 1.000
## 1st Qu.: 8076 Class :character 1st Qu.: 1.000
## Median : 16423 Mode :character Median : 1.000
## Mean : 52519 Mean : 1.813
## 3rd Qu.: 98685 3rd Qu.: 1.000
## Max. :191576 Max. :60.000
Przykładowe wartości:
| set_num | name | year | theme_id | num_parts | img_url |
|---|---|---|---|---|---|
| 001-1 | Gears | 1965 | 1 | 43 | https://cdn.rebrickable.com/media/sets/001-1.jpg |
| 0011-2 | Town Mini-Figures | 1979 | 67 | 12 | https://cdn.rebrickable.com/media/sets/0011-2.jpg |
| 0011-3 | Castle 2 for 1 Bonus Offer | 1987 | 199 | 0 | https://cdn.rebrickable.com/media/sets/0011-3.jpg |
| 0012-1 | Space Mini-Figures | 1979 | 143 | 12 | https://cdn.rebrickable.com/media/sets/0012-1.jpg |
| 0013-1 | Space Mini-Figures | 1979 | 143 | 12 | https://cdn.rebrickable.com/media/sets/0013-1.jpg |
| 0014-1 | Space Mini-Figures | 1979 | 143 | 2 | https://cdn.rebrickable.com/media/sets/0014-1.jpg |
Podsumowanie tabeli:
## set_num name year theme_id
## Length:21880 Length:21880 Min. :1949 Min. : 1
## Class :character Class :character 1st Qu.:2001 1st Qu.:273
## Mode :character Mode :character Median :2012 Median :497
## Mean :2008 Mean :442
## 3rd Qu.:2018 3rd Qu.:608
## Max. :2024 Max. :752
## num_parts img_url
## Min. : 0.0 Length:21880
## 1st Qu.: 3.0 Class :character
## Median : 31.0 Mode :character
## Mean : 161.4
## 3rd Qu.: 139.0
## Max. :11695.0
Przykładowe wartości:
| id | name | parent_id |
|---|---|---|
| 1 | Technic | NA |
| 3 | Competition | 1 |
| 4 | Expert Builder | 1 |
| 16 | RoboRiders | 1 |
| 17 | Speed Slammers | 1 |
| 18 | Star Wars | 1 |
Podsumowanie tabeli:
## id name parent_id
## Min. : 1.0 Length:468 Min. : 1.0
## 1st Qu.:250.5 Class :character 1st Qu.:186.0
## Median :466.0 Mode :character Median :411.0
## Mean :433.5 Mean :360.6
## 3rd Qu.:625.2 3rd Qu.:512.5
## Max. :752.0 Max. :697.0
## NA's :145
| id | name | parent_id | main_theme | root_id |
|---|---|---|---|---|
| 1 | Technic | NA | Technic | NA |
| 3 | Competition | 1 | Technic | NA |
| 4 | Expert Builder | 1 | Technic | NA |
| 16 | RoboRiders | 1 | Technic | NA |
| 17 | Speed Slammers | 1 | Technic | NA |
| 18 | Star Wars | 1 | Technic | NA |
Ze względu na bardzo dużą liczbę motywów, które mogą mieć zestawy Lego, postanowiłem ograniczyć się jedynie do motywów głównych. Aby tego dokonać, dla każdego istniejącego motywu odnajdywany i dodawany jest odpowiedni motyw główny. W ten sposób liczba motywów ograniczyła się z 385 unikalnych motywów do 145 głównych motywów. Nowo utworzony zbiór danych nosi nazwę ‘main_themes’ i jej przykładowe wartości prezentuje powyższa tabela.
| id | set_num | version | name | year | num_parts | theme |
|---|---|---|---|---|---|---|
| 30012 | 42092-1 | 1 | Rescue Helicopter | 2019 | 325 | Technic |
| 143628 | 42096-1 | 2 | Porsche 911 RSR | 2019 | 1580 | Technic |
| 122865 | 42129-1 | 2 | 4x4 Mercedes-Benz Zetros Trial Truck | 2021 | 2131 | Technic |
| 803 | 8680-1 | 1 | Arctic Rescue Base | 1986 | 527 | Technic |
| 30011 | 42091-1 | 1 | Police Pursuit | 2019 | 120 | Technic |
| 36664 | 42097-1 | 1 | Compact Crawler Crane | 2019 | 920 | Technic |
Następnie tabele ‘inventories’ i ‘sets’ łączone są ze sobą wewnętrznie w wyniku czego tracona jest część danych z tabeli ‘inventories’. Utracone wiersze prezentują jednak jedynie pojedyncze minifigurki, dlatego postanowiłem nie uwzględniać tych danych w analizie. Poźniej nowo utworzony zbiór danych jest łączony ze zbiorem ‘main_themes’. Ponadto ograniczyłem liczbę kolumn do: ‘id’, ‘set_num’, ‘version’, ‘name’ (wcześniej ‘name.x’), ‘year’, ‘num_parts’, ‘theme’ (wcześniej ‘main_theme’) oraz zmieniłem typ zmiennej ‘theme’ na typ kategorialny. Ostatecznie powstaje zbiór danych ‘lego_sets’ i jej przykładowe wartości prezentuje powyższa tabela.
| id | set_num | version | name | year | num_parts | theme | minifigs_count |
|---|---|---|---|---|---|---|---|
| 1 | 7922-1 | 1 | McDonald’s Sports Set Number 6 - Orange Vest Snowboarder | 2004 | 5 | Sports | 0 |
| 3 | 3931-1 | 1 | Emma’s Splash Pool | 2012 | 43 | Friends | 1 |
| 4 | 6942-1 | 1 | Zo Weevil | 1999 | 20 | Space | 1 |
| 15 | 5158-1 | 1 | T-Junction, Circle Plates | 1990 | 2 | Service Packs | 0 |
| 16 | 903-1 | 1 | Train Wheels and Couplers | 1969 | 10 | System | 0 |
| 17 | 850950-1 | 1 | Christmas Cat Ornament | 2014 | 34 | Seasonal | 0 |
W ostatnim kroku dodane zostają informacje o liczbie minifigurek w każdym zestawie. Nie każdy zestaw posiada minifigurki, dlatego wykorzystałem połączenie zewnętrzne. Brakujące wartości zostały zastąpione zerami. W powyższej tabeli znajdują się przykładowe wartości.
Podsumowanie uzyskanego zbioru danych ‘lego_sets’:
## id set_num version name
## Min. : 1 Length:23501 Min. : 1.000 Length:23501
## 1st Qu.: 9125 Class :character 1st Qu.: 1.000 Class :character
## Median : 24621 Mode :character Median : 1.000 Mode :character
## Mean : 51747 Mean : 1.144
## 3rd Qu.: 92840 3rd Qu.: 1.000
## Max. :194312 Max. :16.000
##
## year num_parts theme
## Min. :1949 Min. : 0.0 Gear : 3277
## 1st Qu.:2000 1st Qu.: 3.0 Duplo : 1417
## Median :2012 Median : 33.0 Educational and Dacta: 1078
## Mean :2006 Mean : 167.4 Star Wars : 1002
## 3rd Qu.:2018 3rd Qu.: 144.0 Books : 999
## Max. :2024 Max. :11695.0 System : 972
## (Other) :14756
## minifigs_count
## Min. : 0.0000
## 1st Qu.: 0.0000
## Median : 0.0000
## Mean : 0.9425
## 3rd Qu.: 1.0000
## Max. :100.0000
##
| inventory_id | quantity | is_spare | color | rgb | is_trans | part_material | category |
|---|---|---|---|---|---|---|---|
| 10813 | 1 | FALSE | Dark Gray | 6D6E5C | FALSE | Plastic | Baseplates |
| 8694 | 1 | FALSE | Light Gray | 9BA19D | FALSE | Plastic | Baseplates |
| 7239 | 1 | FALSE | Green | 237841 | FALSE | Plastic | Baseplates |
| 103713 | 2 | FALSE | Green | 237841 | FALSE | Plastic | Baseplates |
| 14142 | 1 | FALSE | Dark Bluish Gray | 6C6E68 | FALSE | Plastic | Baseplates |
| 2796 | 1 | FALSE | Blue | 0055BF | FALSE | Plastic | Baseplates |
Dodatkowo dla analizy skoncetrowanej na częściach Lego, połączyłem tabele ‘inventory_parts’, ‘colors’ i ‘part_categories’ tworząc wynikowy zbiór danych ‘lego_parts’, którego przykładowe wartości widoczne są w powyższej tabeli. Ograniczyłem liczbę kolumn do: ‘inventory_id’, ‘quantity’, ‘is_spare’, ‘color’ (wcześniej ‘name.x’), ‘rgb’, ‘is_trans’, ‘part_material’, ‘category’ (wcześniej ‘name’). Zmieniłem typy zmiennych ‘category’, ‘part_material’ i ‘color’ na typy kategorialne. Z kolei zmienne ‘is_trans’ i ‘is_spare’ stały się zmiennymi logicznymi.
Podsumowanie uzyskanego zbioru danych ‘lego_parts’:
## inventory_id quantity is_spare color
## Min. : 1 Min. : 1.00 Mode :logical Black :208830
## 1st Qu.: 9404 1st Qu.: 1.00 FALSE:1104122 White :133815
## Median : 22838 Median : 2.00 TRUE :76865 Light Bluish Gray:123665
## Mean : 50849 Mean : 3.37 Dark Bluish Gray : 92073
## 3rd Qu.: 87088 3rd Qu.: 4.00 Red : 88780
## Max. :194312 Max. :3064.00 Yellow : 66197
## (Other) :467627
## rgb is_trans part_material
## Length:1180987 Mode :logical Cardboard/Paper : 2367
## Class :character FALSE:1113125 Cloth : 2029
## Mode :character TRUE :67862 Flexible Plastic: 245
## Foam : 67
## Metal : 101
## Plastic :1167738
## Rubber : 8440
## category
## Plates :160931
## Bricks : 92632
## Plates Special : 91303
## Bricks Sloped : 68583
## Tiles : 60663
## Plates Round Curved and Dishes: 56183
## (Other) :650692
Z wykresu ciężko coś odczytać ze względu na dużą liczbę odstających wartości oraz skoncentrowanie danych w okolicach zera. Z tego względu postanowiłem pozbyć się wartości najbardziej odstających:
quartiles <- quantile(lego_sets$num_parts, probs=c(.25, .75))
IQR <- IQR(lego_sets$num_parts)
Lower <- quartiles[1] - 1.5*IQR
Upper <- quartiles[2] + 1.5*IQR
lego_sets_num_parts_no_outliers <- subset(lego_sets, lego_sets$num_parts > Lower & lego_sets$num_parts < Upper)
Kolejne 2 wykresy przedstawiają rozkład liczby części Lego po usunięciu odstających wartości:
Z tego co widzimy na wykresie gęstości, najwięcej zestawów składa się tylko z jednej części. W miarę zwiększania się liczby części, wartość funkcji gęstości maleje. Wyjątkiem tutaj jest wzniesienie przy około 100 częściach co oznacza, że powstaje stosunkowo dużo zestawów z taką liczbą części. Podobne wzniesienie można zaobserwować również w okolicach liczby 200, lecz jest ono znacznie mniejsze.
Powyższy wykres został ograniczony do zestawów, które posiadają przynajmniej jedną minifigurkę.
Przeważająca większość zestawów posiada tylko jedną wersję, lecz mimo to zauważalna ilość powstaje w więcej niż jednej wersji.
Ponieważ liczba części ma bardzo dużo wartości odstających o wysokich wartościach, zdecydowałem się na wykorzystanie mediany, ponieważ jest ona bardziej odporna od średniej na wartości odstające.
Na wykresie widać gwałtowny wzrost produkowanych zestawów od końcówki lat 90, a następnie spadek od roku 2002 do 2005. Prawdopodobnie jest to powiązane z kryzysem firmy w tamtym czasie i drastycznymi cięciami kosztów: https://businessinsider.com.pl/firmy/strategie/lego-model-biznesowy-i-strategia-vidiyo-zestawy-hidden-side-nowe-produkty-i-historia/4zzgq1x
Pierwsze minifigurki Lego zaczęły pojawiać się w zestawach od około 1975 roku i od tego czasu ich średnia liczba nie ma trendu rosnącego ani spadkowego. Widać to wyraźniej na wykresie poniżej, który uwzględnia jedynie zestawy z przynajmniej jedną minifigurką:
Wraz z pojawieniem się minifigurek Lego, stosunkowa ilość zestawów z ich udziałem rosła/malała podobnie jak zestawów bez minifigurek.
Zbiór danych zawierający m.in nazwy zestawów i ich ceny pochodzi ze strony: https://www.kaggle.com/datasets/alexracape/lego-sets-and-prices-over-time/data
Istniejący zbiór danych ‘lego_sets’ połączony został wewnętrznie z nowo wczytaną tabelą. Dodane zostały nowe kolumny: ‘theme_group’ (grupa tematyczna), ‘category’ (kategoria zestawu), ‘price’ (Sugerowana Cena Detaliczna Producenta w USD). Ze względu na połączenie wewnętrzne, tracona jest spora część danych - zachowujemy jedynie 6252 wierszy z 23501. Nowo powstały zbiór danych nazwany jest ‘lego_sets_with_price’ i jego wartości przedstawione są w interaktywnej tabeli poniżej:
Zdecydowana większość zestawów miało cenę w wysokości około 10 dolarów. Dodatkowo dostrzec można lokalne wzniesienia funkcji gęstości co mniej więcej 50 dolarów.
W miarę zwiększania zarówno liczby części jak i liczby minifigurek, zestawy stają się średnio droższe.
trainData <- lego_sets_with_price[lego_sets_with_price$year < 2020,]
testData <- lego_sets_with_price[lego_sets_with_price$year >= 2020,]
Zbiór danych podzielony został na dane treningowe i testowe. Dane treningowe to zestawy z rokiem wcześniejszym niż 2020, a pozostałe dane to dane testowe.
X <- c("year", "category", "theme_group", "theme", "num_parts", "minifigs_count")
y <- "price"
cfe <- mkCrossFrameNExperiment(trainData, varlist = X, outcomename = y, verbose = F)
plan <- cfe$treatments
summary(cfe$crossFrame)
## year category_catP category_catN category_catD
## Min. :1991 Min. :0.0006291 Min. :-35.44865 Min. : 0.5774
## 1st Qu.:2010 1st Qu.:0.8860919 1st Qu.: 2.64731 1st Qu.:51.0315
## Median :2013 Median :0.8883297 Median : 2.86430 Median :51.9741
## Mean :2013 Mean :0.7986192 Mean : -0.00188 Mean :48.4188
## 3rd Qu.:2016 3rd Qu.:0.8902170 3rd Qu.: 2.86522 3rd Qu.:52.9725
## Max. :2019 Max. :0.8902170 Max. : 48.81031 Max. :52.9725
## theme_group_catP theme_group_catN theme_group_catD theme_catP
## Min. :0.002202 Min. :-22.51049 Min. : 9.079 Min. :0.0001573
## 1st Qu.:0.079924 1st Qu.:-18.41115 1st Qu.: 25.929 1st Qu.:0.0116389
## Median :0.137823 Median : -1.61755 Median : 30.715 Median :0.0365009
## Mean :0.135079 Mean : 0.01816 Mean : 41.249 Mean :0.0449499
## 3rd Qu.:0.195091 3rd Qu.: 14.48412 3rd Qu.: 67.112 3rd Qu.:0.0855615
## Max. :0.221208 Max. : 85.39680 Max. :115.633 Max. :0.0984896
## theme_catN theme_catD num_parts minifigs_count
## Min. :-34.65366 Min. : 0.00 Min. : 0.0 Min. : 0.000
## 1st Qu.:-14.99429 1st Qu.: 20.88 1st Qu.: 46.0 1st Qu.: 0.000
## Median : -6.27741 Median : 27.07 Median : 141.0 Median : 1.000
## Mean : -0.07061 Mean : 37.34 Mean : 320.2 Mean : 1.884
## 3rd Qu.: 14.75405 3rd Qu.: 49.01 3rd Qu.: 379.0 3rd Qu.: 3.000
## Max. :145.12827 Max. :119.02 Max. :7541.0 Max. :100.000
## category_lev_x_Gear category_lev_x_Normal
## Min. :0.00000 Min. :0.0000
## 1st Qu.:0.00000 1st Qu.:1.0000
## Median :0.00000 Median :1.0000
## Mean :0.09815 Mean :0.8882
## 3rd Qu.:0.00000 3rd Qu.:1.0000
## Max. :1.00000 Max. :1.0000
## theme_group_lev_x_Action_slash_Adventure theme_group_lev_x_Basic
## Min. :0.0000 Min. :0.00000
## 1st Qu.:0.0000 1st Qu.:0.00000
## Median :0.0000 Median :0.00000
## Mean :0.1191 Mean :0.02349
## 3rd Qu.:0.0000 3rd Qu.:0.00000
## Max. :1.0000 Max. :1.00000
## theme_group_lev_x_Constraction theme_group_lev_x_Licensed
## Min. :0.00000 Min. :0.0000
## 1st Qu.:0.00000 1st Qu.:0.0000
## Median :0.00000 Median :0.0000
## Mean :0.04782 Mean :0.2158
## 3rd Qu.:0.00000 3rd Qu.:0.0000
## Max. :1.00000 Max. :1.0000
## theme_group_lev_x_Miscellaneous theme_group_lev_x_Model_making
## Min. :0.0000 Min. :0.00000
## 1st Qu.:0.0000 1st Qu.:0.00000
## Median :0.0000 Median :0.00000
## Mean :0.1906 Mean :0.06607
## 3rd Qu.:0.0000 3rd Qu.:0.00000
## Max. :1.0000 Max. :1.00000
## theme_group_lev_x_Modern_day theme_group_lev_x_Pre_minus_school
## Min. :0.0000 Min. :0.00000
## 1st Qu.:0.0000 1st Qu.:0.00000
## Median :0.0000 Median :0.00000
## Mean :0.1443 Mean :0.08221
## 3rd Qu.:0.0000 3rd Qu.:0.00000
## Max. :1.0000 Max. :1.00000
## theme_group_lev_x_Racing theme_group_lev_x_Technical theme_lev_x_Bionicle
## Min. :0.00000 Min. :0.00000 Min. :0.00000
## 1st Qu.:0.00000 1st Qu.:0.00000 1st Qu.:0.00000
## Median :0.00000 Median :0.00000 Median :0.00000
## Mean :0.02118 Mean :0.04908 Mean :0.02789
## 3rd Qu.:0.00000 3rd Qu.:0.00000 3rd Qu.:0.00000
## Max. :1.00000 Max. :1.00000 Max. :1.00000
## theme_lev_x_City theme_lev_x_Collectible_Minifigures theme_lev_x_Creator
## Min. :0.00000 Min. :0.00000 Min. :0.00000
## 1st Qu.:0.00000 1st Qu.:0.00000 1st Qu.:0.00000
## Median :0.00000 Median :0.00000 Median :0.00000
## Mean :0.08997 Mean :0.02265 Mean :0.04677
## 3rd Qu.:0.00000 3rd Qu.:0.00000 3rd Qu.:0.00000
## Max. :1.00000 Max. :1.00000 Max. :1.00000
## theme_lev_x_Duplo theme_lev_x_Friends theme_lev_x_Gear theme_lev_x_Ninjago
## Min. :0.00000 Min. :0.00000 Min. :0.0000 Min. :0.00000
## 1st Qu.:0.00000 1st Qu.:0.00000 1st Qu.:0.0000 1st Qu.:0.00000
## Median :0.00000 Median :0.00000 Median :0.0000 Median :0.00000
## Mean :0.08242 Mean :0.04677 Mean :0.0948 Mean :0.04677
## 3rd Qu.:0.00000 3rd Qu.:0.00000 3rd Qu.:0.0000 3rd Qu.:0.00000
## Max. :1.00000 Max. :1.00000 Max. :1.0000 Max. :1.00000
## theme_lev_x_Seasonal theme_lev_x_Star_Wars theme_lev_x_Technic
## Min. :0.00000 Min. :0.0000 Min. :0.00000
## 1st Qu.:0.00000 1st Qu.:0.0000 1st Qu.:0.00000
## Median :0.00000 Median :0.0000 Median :0.00000
## Mean :0.02685 Mean :0.0862 Mean :0.03586
## 3rd Qu.:0.00000 3rd Qu.:0.0000 3rd Qu.:0.00000
## Max. :1.00000 Max. :1.0000 Max. :1.00000
## theme_lev_x_Racers price
## Min. :0.00000 Min. : 1.49
## 1st Qu.:0.00000 1st Qu.: 9.99
## Median :0.00000 Median : 19.99
## Mean :0.02034 Mean : 37.83
## 3rd Qu.:0.00000 3rd Qu.: 49.99
## Max. :1.00000 Max. :849.99
Do przygotowania danych do zadania regresji wykorzystany został pakiet vtreat, który potrafi m.in zamieniać zmienne kategorialne na numeryczne lub tworzyć nowe zmienne w oparciu o istniejące (np. zmienne wpływu, zmienne zawierające częstość występowania zmiennych). Najbardziej istotne zmienne są następnie automatycznie wybierane. Podsumowanie tych zmiennych znajduje się powyżej.
Jako model postanowiłem wybrać drzewa wzmacniane gradientowo, a konkretnie pakiet xgboost.
trainMatrix <- as.matrix(subset(cfe$crossFrame, select = -price))
cv <- xgb.cv(trainMatrix, label = trainData$price,
params = list(objective = "reg:squarederror"),
nfold = 5,
nrounds = 100,
print_every_n = 10)
## [1] train-rmse:46.256207+0.741671 test-rmse:46.585969+3.642867
## [11] train-rmse:11.436735+0.303852 test-rmse:17.191881+2.492174
## [21] train-rmse:10.008665+0.370647 test-rmse:16.727532+2.092106
## [31] train-rmse:9.317084+0.434719 test-rmse:16.630321+2.044780
## [41] train-rmse:8.729246+0.425535 test-rmse:16.581071+2.064203
## [51] train-rmse:8.310997+0.436576 test-rmse:16.575638+2.065177
## [61] train-rmse:7.996495+0.461478 test-rmse:16.598380+2.063306
## [71] train-rmse:7.694729+0.442138 test-rmse:16.638898+2.012000
## [81] train-rmse:7.471597+0.455581 test-rmse:16.624840+2.019884
## [91] train-rmse:7.293423+0.459289 test-rmse:16.648787+1.982609
## [100] train-rmse:7.165383+0.465258 test-rmse:16.676541+1.964070
evalframe <- as.data.frame(cv$evaluation_log)
Początkowo odbywa się faza dostrajania hiperparametru ‘nrounds’ oznaczającego liczbę tworzonych drzew. Poniżej znajduje się wykres z uzyskanymi wynikami i wybraną liczbą drzew oznaczoną niebieską linią:
model <- xgboost(data = trainMatrix,
label = trainData$price,
params = list(objective = "reg:squarederror"),
nrounds = NROUNDS,
verbose = FALSE)
model
## ##### xgb.Booster
## raw: 146.9 Kb
## call:
## xgb.train(params = params, data = dtrain, nrounds = nrounds,
## watchlist = watchlist, verbose = verbose, print_every_n = print_every_n,
## early_stopping_rounds = early_stopping_rounds, maximize = maximize,
## save_period = save_period, save_name = save_name, xgb_model = xgb_model,
## callbacks = callbacks)
## params (as set within xgb.train):
## objective = "reg:squarederror", validate_parameters = "TRUE"
## xgb.attributes:
## niter
## callbacks:
## cb.evaluation.log()
## # of features: 36
## niter: 47
## nfeatures : 36
## evaluation_log:
## iter train_rmse
## 1 46.168412
## 2 34.793118
## ---
## 46 8.907868
## 47 8.894319
Następnie odbywa się właściwy trening modelu z odpowiednio ustawionym parametrem ‘nrounds’.
W poniższej tabeli znajdują się wyniki predykcji modelu i wartości rzeczywiste:
Model uzyskał następujący wynik dla współczynnika RMSE:
## [1] 33.55103
RMSE można interpretować jako średnią oczekiwaną różnicę +/- między wartością przewidywaną a rzeczywistą.
Powyżej znajduje się wykres zależności między ceną rzeczywistą a przewidywaną. Mimo tego, że istnieją liczne obserwacje dla których przewidywania modelu znacznie odbiegają od rzeczywistości, to w ogólności radzi sobie on dość dobrze.